package com.azhoucode.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.azhoucode.constant.RedisConstant;
import com.azhoucode.entity.*;
import com.azhoucode.service.TableService;
import com.azhoucode.util.FreeMarkerUtil;
import com.azhoucode.util.RedisCacheUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toCollection;

/**
 * @description: 单表实现
 * @author: azhou
 * @create: 2021-12-15 10:51
 **/
@Service
public class TableServiceImpl implements TableService {

    private static final String MODIFY = "modify";
    private static final String SHOW = "show";
    private static final String SEARCH = "search";

    @Autowired
    private FreeMarkerUtil freeMarkerUtil;

    @Override
    public void addTableConfiguration(TableEntity tableEntity, String random) throws Exception {
        TableParam tableParam = new TableParam();
        tableParam.setTableName(tableEntity.getTableName());
        tableParam.setClassName(freeMarkerUtil.getEntityName(tableEntity.getTableName()));
        tableParam.setUnClassName(freeMarkerUtil.getEntityNameLower(tableEntity.getTableName()));
        tableParam.setTableComment(StrUtil.isEmpty(tableEntity.getTableComment()) ? tableEntity.getTableName() : tableEntity.getTableComment());
        tableParam.setShowColList(buildSearchParam(tableEntity, true));
        List<SearchParam> searchParamList = new ArrayList<>();
        searchParamList.addAll(buildSearchParam(tableEntity, true));
        Map<String, List<SearchParam>> stringListMap = buildVueTableData(tableEntity, true);
        List<SearchParam> modifyList = stringListMap.get(MODIFY);
        List<SearchParam> showList = stringListMap.get(SHOW);
        List<SearchParam> searchList = stringListMap.get(SEARCH);
        // 存在子表配置
        List<TableEntity> sonTableEntities = tableEntity.getSonTableEntities();
        List<String> correlationList = tableEntity.getCorrelationList();
        if (CollectionUtil.isNotEmpty(sonTableEntities) && CollectionUtil.isNotEmpty(correlationList)) {
            List<SearchParam> sonTableColEntities = new ArrayList<>();
            tableParam.setHasSonTable(true);
            for (TableEntity sonTableEntity : sonTableEntities) {
                Map<String, List<SearchParam>> stringListMap1 = buildVueTableData(sonTableEntity, false);
                List<SearchParam> modifyList1 = stringListMap1.get(MODIFY);
                modifyList.addAll(modifyList1);
                List<SearchParam> showList1 = stringListMap1.get(SHOW);
                showList.addAll(showList1);
                List<SearchParam> searchList1 = stringListMap1.get(SEARCH);
                searchList.addAll(searchList1);
                sonTableColEntities.addAll(buildSearchParam(sonTableEntity, false));
                searchParamList.addAll(buildSearchParam(sonTableEntity, false));
            }
            tableParam.setShowSonTableColList(sonTableColEntities);
            if (CollectionUtil.isNotEmpty(correlationList)) {
                tableParam.setCorrelation(correlationList.stream().collect(Collectors.joining("\n\r")));
            }
        }
        tableParam.setHasUpload(checkHasUpload(tableEntity));
        tableParam.setSearchColsList(searchParamList);
        tableParam.setVueModifyColList(modifyList);
        tableParam.setVueShowColList(showList);
        tableParam.setVueSearchColList(searchList);
        if (CollectionUtil.isNotEmpty(tableEntity.getEnumsEntities())) {
            List<EnumsEntity> enumsEntities = tableEntity.getEnumsEntities();
            List<EnumsEntity> list = enumsEntities.stream().collect(collectingAndThen(toCollection(() ->
                    new TreeSet<>(comparing(n -> n.getColName()))), ArrayList::new));
            tableParam.setUpdateEnumsLists(list);
        }
        if (CollectionUtil.isNotEmpty(tableEntity.getTableEnumsEntities())) {
            List<EnumsEntity> enumsEntities = tableEntity.getTableEnumsEntities();
            List<EnumsEntity> list = enumsEntities.stream().collect(collectingAndThen(toCollection(() ->
                    new TreeSet<>(comparing(n -> n.getColName()))), ArrayList::new));
            tableParam.setTableEnumsEntities(list);
        }
        if(CollectionUtil.isNotEmpty(tableEntity.getSelectEntities())) {
            List<SelectEntity> selectEntities = tableEntity.getSelectEntities();
            List<SelectEntity> list = selectEntities.stream().collect(collectingAndThen(toCollection(() ->
                    new TreeSet<>(comparing(n -> n.getFromTableName()))), ArrayList::new));
            List<SelectEntity> collect = list.stream().map(item -> {
                item.setClassName(freeMarkerUtil.getEntityName(item.getFromTableName()));
                item.setUnClassName(freeMarkerUtil.getEntityNameLower(item.getFromTableName()));
                item.setPropertyName(freeMarkerUtil.getEntityNameLower(item.getColName()));
                item.setNameCol(freeMarkerUtil.getEntityName(item.getNameCol()));
                item.setValueCol(freeMarkerUtil.getEntityName(item.getValueCol()));
                return item;
            }).collect(Collectors.toList());
            tableParam.setSelectEntities(collect);
        }
        RedisCacheUtils.lpush(String.format(RedisConstant.TABLE_LIST, random), JSON.toJSONString(tableParam));
    }

    /**
     * 检验是否需要文件上传
     *
     * @return
     */
    public Boolean checkHasUpload(TableEntity tableEntity) {
        List<TableColEntity> tableColEntityList = tableEntity.getTableColEntityList();
        boolean flag = false;
        if (CollectionUtil.isEmpty(tableColEntityList)) return flag;
        for (TableColEntity tableColEntity : tableColEntityList) {
            if (tableColEntity.getUploadImg()) {
                flag = true;
                break;
            }
        }
        return flag;
    }

    /**
     * 构建主表的搜索列
     *
     * @param tableEntity
     * @param isMain
     * @return
     */
    public List<SearchParam> buildSearchParam(TableEntity tableEntity, Boolean isMain) {
        List<SearchParam> searchParamList = new ArrayList<>();
        List<TableColEntity> tableColEntityList = tableEntity.getTableColEntityList();
        // 处理主表
        for (TableColEntity tableColEntity : tableColEntityList) {
            SearchParam searchParam = new SearchParam();
            searchParam.setColName(tableColEntity.getColName());
            searchParam.setPropertyType(tableColEntity.getParamType());
            searchParam.setPropertyName(freeMarkerUtil.underlineToHump(tableColEntity.getColName()));
            searchParam.setPropertyChinaName(tableColEntity.getChinaName());
            searchParam.setCompareWay(tableColEntity.getCompareType());
            // 下划线转驼峰
            searchParam.setFromTableName(freeMarkerUtil.underlineToHump(tableEntity.getTableName()));
            if (isMain) {
                searchParamList.add(searchParam);
            } else {
                if (tableColEntity.getTableShow()) {
                    searchParamList.add(searchParam);
                }
            }
        }
        return searchParamList;
    }

    /**
     * 构建前端vue表格中的各种参数
     *
     * @param tableEntity
     * @return
     */
    private Map<String, List<SearchParam>> buildVueTableData(TableEntity tableEntity, Boolean isMain) {
        Map<String, List<SearchParam>> map = new HashMap<>(6);
        List<SearchParam> vueShowColList = new ArrayList<>();
        List<SearchParam> vueModifyColList = new ArrayList<>();
        List<SearchParam> vueSearchColList = new ArrayList<>();
        List<TableColEntity> tableColEntityList = tableEntity.getTableColEntityList();
        for (TableColEntity tableColEntity : tableColEntityList) {
            // 修改属性
            if (tableColEntity.getUpdateShow() && isMain) {
                SearchParam searchParam = new SearchParam();
                searchParam.setPropertyChinaName(searchParam.getPropertyChinaName());
                searchParam.setPropertyName(freeMarkerUtil.underlineToHump(tableColEntity.getColName()));
                searchParam.setColName(tableColEntity.getColName());
                searchParam.setPropertyType(tableColEntity.getParamType());
                searchParam.setPropertyChinaName(tableColEntity.getChinaName());
                searchParam.setCompareType(tableColEntity.getCompareType());
                searchParam.setShowType(tableColEntity.getShowType());
                searchParam.setUpdateType(tableColEntity.getUpdateType());
                vueModifyColList.add(searchParam);
            }
            if (tableColEntity.getTableShow()) {
                SearchParam searchParam = new SearchParam();
                searchParam.setPropertyChinaName(searchParam.getPropertyChinaName());
                searchParam.setPropertyName(freeMarkerUtil.underlineToHump(tableColEntity.getColName()));
                searchParam.setColName(tableColEntity.getColName());
                searchParam.setPropertyChinaName(tableColEntity.getChinaName());
                searchParam.setCompareType(tableColEntity.getCompareType());
                searchParam.setIsUploadCol(tableColEntity.getUploadImg());
                searchParam.setPropertyType(tableColEntity.getParamType());
                searchParam.setShowType(tableColEntity.getShowType());
                searchParam.setUpdateType(tableColEntity.getUpdateType());
                vueShowColList.add(searchParam);
            }
            if (tableColEntity.getSearchShow()) {
                SearchParam searchParam = new SearchParam();
                searchParam.setPropertyChinaName(searchParam.getPropertyChinaName());
                searchParam.setPropertyName(freeMarkerUtil.underlineToHump(tableColEntity.getColName()));
                searchParam.setColName(tableColEntity.getColName());
                searchParam.setPropertyChinaName(tableColEntity.getChinaName());
                searchParam.setPropertyType(tableColEntity.getParamType());
                searchParam.setCompareType(tableColEntity.getCompareType());
                searchParam.setShowType(tableColEntity.getShowType());
                searchParam.setUpdateType(tableColEntity.getUpdateType());
                vueSearchColList.add(searchParam);
            }
        }
        map.put(SHOW, vueShowColList);
        map.put(MODIFY, vueModifyColList);
        map.put(SEARCH, vueSearchColList);
        return map;
    }

}
